﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

#if SILVERLIGHT
using System.Windows;
using GameEngineSL.SilverlightCompatibility;
#else
using System.Drawing;
#endif

namespace GameEngine.Worlds
{
    public abstract class Map
    {
        // Map data.
        protected float[ , ] mapData;
        // Width and height of the mapData array.
        protected Size mapDataSize;
        // Location of the map in the world. Allows the use of custom units.
        protected RectangleF mapLocation;
    
        public Map(Size mapSize, RectangleF mapLocation)
        {
            // Allocate mapData, a 2D array
            this.mapData = new float[(int)mapSize.Width, (int)mapSize.Height];
            this.mapLocation = mapLocation;
        }

        public double this[float x, float y]
        {
            get
            {
                // Round x and y down to integers.
                int xFloor = (int)Math.Floor(x);
                int yFloor = (int)Math.Floor(y);

                // Get the fractional part of x and y.
                float xFract = x - (float)xFloor;
                float yFract = y - (float)yFloor;
                
                // Return linear interpolation of four points on map.
                return interpolate(xFract, yFract,
                    mapData[xFloor, yFloor],
                    mapData[xFloor, yFloor + 1],
                    mapData[xFloor + 1, yFloor],
                    mapData[xFloor + 1, yFloor + 1]);
            }
        }

        /// <summary>
        /// Returns the position (origin and size) of the map in world units.
        /// </summary>
        public RectangleF MapLocation
        {
            get
            {
                return mapLocation;
            }
        }

        /// <summary>
        /// Returns the size of the mapData array.
        /// </summary>
        public Size MapDataSize
        {
            get
            {
                return mapDataSize;
            }
        }

        protected PointF convertWorldToMap(PointF worldCoordinates)
        {
            return new PointF(
                ((worldCoordinates.X - mapLocation.X) / mapLocation.Width)  * (float)mapDataSize.Width,
                ((worldCoordinates.Y - mapLocation.Y) / mapLocation.Height) * (float)mapDataSize.Width);
        }

        protected float interpolate(float x, float y, float valueX0Y0, float valueX0Y1, float valueX1Y0, float valueX1Y1)
        {
            // Linear interpolation for x fraction
            float interpolationY0 = (valueX0Y0 * (1 - x)) + (valueX1Y0 * x);
            float interpolationY1 = (valueX0Y1 * (1 - x)) + (valueX1Y1 * x);
            return interpolationY0 * (1 - y) + 
                   interpolationY1 *      y;
        }
    }
}
